package cn.t12.qg.goodsconsumer.service;

import cn.t12.qg.goodsconsumer.vo.GoodsVo;
import cn.t12.qg.service.user.GoodsService;
import cn.t12.qg.service.user.GoodsTempStockService;
import cn.t12.qg.service.user.OrderService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qg.common.Constants;
import com.qg.pojo.QgGoods;
import com.qg.pojo.QgGoodsTempStock;
import com.qg.pojo.QgOrder;
import com.qg.pojo.QgUser;
import com.qg.utils.IdWorker;
import com.qg.utils.RedisUtil;

import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.jms.Queue;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class LocalGoodsServiceImpl implements LocalGoodsService {
    private static final Logger LOGGER = LoggerFactory.getLogger(LocalGoodsServiceImpl.class);

    @DubboReference(version = "1.0.0")
    private GoodsService goodsService;

    @DubboReference(version = "1.0.0")
    private GoodsTempStockService tempStockService;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public GoodsVo getById(String id) {
        GoodsVo goodsVo = null;
        // 从缓存中获取
        String jsonString = redisUtil.getStr(Constants.goodsPrefix + id); // key?
        // 如果没有
        if (jsonString == null) {
            // 调用 provider 进行查询
            QgGoods qgGoods = goodsService.getById(id);
            goodsVo = new GoodsVo();
            BeanUtils.copyProperties(qgGoods, goodsVo);

            // 当前库存 = 原始库存 - 已锁定库存和已支付的库存
            Map<String, Object> map = new HashMap<>();
            map.put("locked", 0);
            map.put("success", 1);
            Integer stock = tempStockService.countBy(map);
            //goodsVo.setCurrentStock(); // ?
            goodsVo.setCurrentStock(qgGoods.getStock() - stock);
            // 存到 redis中,方便后续继续使用
            redisUtil.setStr(Constants.goodsPrefix + id, JSON.toJSONString(goodsVo));
        } else {
            goodsVo = JSONObject.parseObject(jsonString, GoodsVo.class);
        }
        return goodsVo;
    }

    @DubboReference(version = "1.0.0")
    private OrderService orderService;

    // select num from goods where id=1 for update
    // 新增没有锁,修改是有锁 在数据库中
    @JmsListener(destination = "qg_goods_queue")
    public void handlerQgGoodsMessage(Map<String, String> map) throws InterruptedException {
        LOGGER.info("开始处理抢购消息: [ {} ]", map);
        GoodsVo goodsVo = null;
        String goodsId = map.get("goodsId");
        String token = map.get("token");
        // 获取分布式锁
        String lockKey = "GoodLock:" + goodsId;

        while (!redisUtil.lock(lockKey, 300)) {  // !true
            Thread.sleep(3);
        }

        // 如果大于0,判断用户是否已经抢购过,
        String userJsonString = redisUtil.getStr(Constants.tokenPrefix + token);
        QgUser qgUser = JSONObject.parseObject(userJsonString, QgUser.class);
        String goodsExistsBuyKey = "goodsExistsBuy:" + goodsId + ":" + qgUser.getId();

        //Boolean exists = tempStockService.exists(qgUser.getId(),goodsId);

        // 1 表示成功 0 表示已经卖完 2表示之前已经成功抢购过的

        // 如果 在redis中已经有用户抢购的标识,说明已经抢过啦
        String status = redisUtil.getStr(goodsExistsBuyKey);
        if (status != null) {
            redisUtil.setStr(goodsExistsBuyKey, "2");
            // 要先释放锁
            redisUtil.unLock(lockKey);
            return;
        }
        // 如果是之前抢过,但是当前redis没有标识了,重新放一个标识
        if (tempStockService.exists(qgUser.getId(), goodsId)) {
            redisUtil.setStr(goodsExistsBuyKey, "2");
            // 要先释放锁
            redisUtil.unLock(lockKey);
            return;
        }

        // 从缓存中获取
        String jsonString = redisUtil.getStr(Constants.goodsPrefix + goodsId);
        goodsVo = JSONObject.parseObject(jsonString, GoodsVo.class);
        // user:20  goodscount: 100
        // 判断商品的当前库存是否大于0
        if (goodsVo.getCurrentStock() <= 0) {
            // 没有商品了,直接标识抢购失败
            redisUtil.setStr(goodsExistsBuyKey, "0");
            // 要先释放锁
            redisUtil.unLock(lockKey);
            return;
        }

        //如果没有抢购的话,跟新当前库存,然后保存抢购的记录
        goodsVo.setCurrentStock(goodsVo.getCurrentStock() - 1);
        redisUtil.setStr(Constants.goodsPrefix + goodsId, JSON.toJSONString(goodsVo));
        // 保存抢购记录
        QgGoodsTempStock tempStock = new QgGoodsTempStock();
        tempStock.setId(IdWorker.getId());
        tempStock.setGoodsId(goodsId);
        tempStock.setUserId(qgUser.getId());
        tempStock.setStatus(0);
        tempStock.setCreatedTime(new Date());
        tempStockService.insert(tempStock);
        // 保存订单

        QgOrder qgOrder = new QgOrder();
        // 订单的独一无二的主键值
        qgOrder.setId(IdWorker.getId());
        qgOrder.setUserId(qgUser.getId());
        // 订单的业务编号
        qgOrder.setOrderNo(IdWorker.getId());
        qgOrder.setGoodsId(goodsId);
        qgOrder.setNum(1);
        qgOrder.setAmount(goodsVo.getPrice());
        qgOrder.setStatus(0);
        qgOrder.setCreatedTime(new Date());
        orderService.saveOrder(qgOrder);

        // 在redis中存放一个用户抢购过的标识
        redisUtil.setStr(goodsExistsBuyKey, "1");
        // 要先释放锁
        redisUtil.unLock(lockKey);
        // 返回抢购成功的信息
        //return "抢购成功!";
    }

    @Resource
    private JmsMessagingTemplate jmsMessagingTemplate;
    @Resource(name = "goodsQueue")
    private Queue qgGoodsQueue;

    @Override
    public void sendQgGoodsMessage(String goodsId, String token) {
        Map<String, Object> map = new HashMap<>();
        map.put("goodsId", goodsId);
        map.put("token", token);
        jmsMessagingTemplate.convertAndSend(qgGoodsQueue, map);
        LOGGER.info("发送抢购消息成功: [ {} ]", map);
    }

    @Override
    public String getGoodsStatus(String goodsId, String token) {
        String userJsonString = redisUtil.getStr(Constants.tokenPrefix + token);
        QgUser qgUser = JSONObject.parseObject(userJsonString, QgUser.class);
        String goodsExistsBuyKey = "goodsExistsBuy:" + goodsId + ":" + qgUser.getId();
        String status = redisUtil.getStr(goodsExistsBuyKey);
        return status == null ? "-1" : status;
    }
}
